from utils.database_table import RSNodeTable, FusedRoadTable, RemoteSensingRoadTable, ReportRoadTable, Table
from prepocessing.manual import ManualTool
from prepocessing.remove_pseudo_nodes import RemovePseudoNodesTool
from prepocessing.split import SplitTool
from prepocessing.remove_dangling import DanglingTool
from prepocessing.snap_nodes import SnapTool, FuseSnapTool
from match.match import MatchTool
from utils.basic_function import *
from shapely.geometry import Polygon
from topology_construction.label_nodes import RSTopologyTool
from stake.stake import StakeTool, label_stake_direction, compute_stakes, get_all_stakes
from merge.FuseTool import BufferIterationTool, ChangeDetectionTool
from merge.fuse_postprocessing import fuse_postprocessing
from stake.number_new_roads import number_all_new_road
from stake.hectometer_stake import hectometer_stake_layer
from prepocessing.shp_to_pg import *
from accuracy_assessment.match_accuracy import *
from accuracy_assessment.stake_accuracy import *
import time
import settings


def rs_road_preprocessing(table_name):
    t0 = time.time()

    rs_table = RemoteSensingRoadTable(table_name)
    rs_table.restore_table_from(rs_table.name + "_backup")

    # 找出重叠、多次相交(自相交，环结构)，手动改正
    mt = ManualTool(rs_table)
    mt.find_all()

    # 去除伪结点
    rp = RemovePseudoNodesTool(rs_table, CLUSTER_TOLERANCE_R)
    rp.remove_pseudo_nodes_table()
    rs_table.create_backup("fixpn_backup")
    print(time.time()-t0)

    # 捕捉+去除伪结点+检查重叠
    rs_table.restore_table_from(rs_table.name + "_fixpn_backup")
    snapper = SnapTool(rs_table, CLUSTER_TOLERANCE_R, 30, 5, 50, True)
    snapper.snap_nodes_table()
    rp = RemovePseudoNodesTool(rs_table, CLUSTER_TOLERANCE_R)
    rp.remove_pseudo_nodes_table()
    mt = ManualTool(rs_table)
    mt.find_all()
    rs_table.create_backup("snap_backup")
    print("时间", time.time() - t0)

    # 相交打断
    splitter = SplitTool(rs_table, CLUSTER_TOLERANCE_R, 1)
    splitter.split_intersects_table()
    rs_table.create_backup("split_i")
    print("时间", time.time() - t0)

    # 去除毛刺和孤立路段+去除伪结点+检查重叠
    dt = DanglingTool(rs_table, CLUSTER_TOLERANCE_R, 20, 50, 20, 50)
    dt.remove_dangling_table()
    print(dt.check_dangle_list)  # todo 注意这里需要人工检查
    print(dt.check_isolate_list)
    rp = RemovePseudoNodesTool(rs_table, CLUSTER_TOLERANCE_R)
    rp.remove_pseudo_nodes_table()
    mt = ManualTool(rs_table)
    mt.find_all()
    rs_table.create_backup("dangle_backup")
    print("时间", time.time() - t0)


def merge_rp_tables(rp_prefix, merged_rp_table_name, extent=None):
    # 将所有道路合并到同一个图层
    merged_rp_table = ReportRoadTable(merged_rp_table_name)
    with conn:
        with conn.cursor() as cursor:
            if extent:
                where = f"""
                where st_intersects({merged_rp_table.geom},
                st_geomfromewkt('SRID={merged_rp_table.srid};{extent.wkt}')
                )
            """
            else:
                where = ""

            merged_rp_table.create_table(drop=True)
            cols = list(merged_rp_table.dtype_dict.keys())
            cols.remove(merged_rp_table.length)
            cols.remove(merged_rp_table.pk)
            for r_class in R_CLASS_LIST[:-1]:
                sql = f"""insert into {merged_rp_table.name}({','.join(cols)},{merged_rp_table.length}) 
                    select {','.join(cols)},st_length({merged_rp_table.geom}) from {rp_prefix}_{r_class.lower()} {where}"""
                cursor.execute(sql)

    merged_rp_table.create_index(merged_rp_table.geom, True)
    merged_rp_table.create_backup("backup")


def split_rp(merged_rp_table_name, rp_prefix):
    r_class_list = R_CLASS_LIST[:-1]
    rp_table = ReportRoadTable(merged_rp_table_name)

    # # 上报路网处理
    rp_table.restore_table_from("rp_all_backup")

    # 找出重叠、多次相交(自相交，环结构)，手动改正
    mt = ManualTool(rp_table)
    mt.find_all()
    rp_table.create_backup("manual_backup")

    # 捕捉+去除伪结点+检查重叠
    rp_table.restore_table_from(rp_table.name + "_manual_backup")
    snapper = SnapTool(rp_table, CLUSTER_TOLERANCE_R, 5, 5, transform_distance=5, end_priority=False)  # 直接捕捉到最近点，不端点优先
    snapper.snap_nodes_table()
    mt = ManualTool(rp_table)
    mt.find_all()
    rp_table.create_backup("snap_backup")

    # 相交打断 保留一定的属性，以备后续重新合并
    rp_table.restore_table_from(rp_table.name + "_snap_backup")
    splitter = SplitTool(rp_table, CLUSTER_TOLERANCE_R, 1, preserve_col_list=[rp_table.segment_code])
    splitter.split_intersects_table()
    rp_table.create_backup("split_i")

    # 上报路网分层
    with conn:
        with conn.cursor() as cursor:
            for r_class in r_class_list:
                sql = f"drop table if exists {rp_prefix}_{r_class};" \
                      f"select * into {rp_prefix}_{r_class} from {rp_table.name} where substring({rp_table.segment_code},1,1)='{r_class}'"
                cursor.execute(sql)


def match(rs_table_name, rp_prefix, match_rs_prefix):
    r_class_list = R_CLASS_LIST[:-1]
    rs_table = RemoteSensingRoadTable(rs_table_name)

    # 遥感路网按上报路网打断
    rs_table.restore_table_from(rs_table.name + "_dangle_backup")
    splitter = SplitTool(rs_table, 50, None)
    for r_class in r_class_list:
        rp_layer = ReportRoadTable(f"{rp_prefix}_{r_class}".lower())
        splitter.split_by_layer(rp_layer)
        print(rp_layer.name)
    rs_table.create_backup("split_all")

    # 恢复遥感路网数据
    rs_table.restore_table_from(rs_table.name + "_split_all")
    # 新版匹配，上报匹配到遥感
    mt = MatchTool(rs_table, 50, 100, 20, ldbm_col=ReportRoadTable.pk)
    for r_class in r_class_list:
        rp_table = ReportRoadTable(f"{rp_prefix}_{r_class}".lower())
        mt.match_table_reverse(rp_table)
        mt.match_postprocessing(rp_table)
        match_table = RemoteSensingRoadTable(f"{match_rs_prefix}_{r_class}".lower())
        rs_table.move_rows(match_table, where=f"where {rs_table.match_road} is not null")
        match_table.add_primary_key()
        match_table.create_index(match_table.geom, is_geom=True)
    match_table = RemoteSensingRoadTable(f"{match_rs_prefix}_n")
    rs_table.move_rows(match_table)
    match_table.add_primary_key()
    match_table.create_index(match_table.geom, is_geom=True)

def match_check(rp_prefix, match_rs_prefix):
    r_class_list = R_CLASS_LIST[:-1]
    check = MatchAccuracyAssess()
    for r_class in r_class_list:
        rp_layer = ReportRoadTable(f"{rp_prefix}_{r_class}".lower())
        match_layer = RemoteSensingRoadTable(f"{match_rs_prefix}_{r_class}".lower())
        check.no_match_road(rp_layer.name, match_layer.name)
        check.partly_match_road(rp_layer.name, match_layer.name, 0.65)


def fuse_bufferIteration(source_rp_prefix, match_rs_prefix, rp_prefix, fuse_prefix):
    r_class_list = R_CLASS_LIST[:-1]

    bufferIteration = BufferIterationTool(Iteration_num=5)
    for r_class in r_class_list:
        source_rp_layer = ReportRoadTable(f"{source_rp_prefix}_{r_class}".lower())
        rp_layer = ReportRoadTable(f"{rp_prefix}_{r_class}".lower())
        match_layer = RemoteSensingRoadTable(f"{match_rs_prefix}_{r_class}".lower())
        join_layer = ReportRoadTable(f'{fuse_prefix}_{r_class}'.lower())
        bufferIteration.buffer_iteration_workflow(source_rp_table=source_rp_layer, rp_table=rp_layer, match_table=match_layer,
                                                join_table=join_layer)


def fuse_changeDetect(src_prefix, fuse_input_rs_prefix, fuse_input_rp_prefix, fuse_output_prefix,extent):
    r_class_list = R_CLASS_LIST[:-1]
    changeDetectionTool = ChangeDetectionTool(extent)
    for r_class in r_class_list:
        print(r_class)
        src_rp_name = ReportRoadTable(f"{src_prefix}_{r_class.lower()}")
        rp_layer = ReportRoadTable(f"{fuse_input_rp_prefix}_{r_class.lower()}")
        rs_layer = RemoteSensingRoadTable(f"{fuse_input_rs_prefix}_{r_class.lower()}")
        output_layer = ReportRoadTable(f"{fuse_output_prefix}_{r_class.lower()}")
        changeDetectionTool.change_detection_workflow(src_rp_name, rs_layer, rp_layer, output_layer)


def label_rs_nodes(node_table_name, road_prefix):
    rs_node_table = RSNodeTable(node_table_name)
    rs_node_table.create_table(drop=True)
    rs_node_table.add_primary_key()
    rs_node_table.create_index(rs_node_table.geom, True)
    tb = RSTopologyTool(rs_node_table, road_prefix)
    tb.label_nodes_workflow()


def load_extent(shp_path):
    df = geopd.read_file(shp_path)
    geom = df.loc[0, "geometry"]  # todo 检查坐标系和投影
    return geom


def hectometer_stake_interpolate(HECTOR_STAKE_PREFIX,FUSE_OUTPUT_PREFIX):
    r_class_list = R_CLASS_LIST[:-1]
    for r_class in r_class_list:
        fuse_table = FusedRoadTable(f"{FUSE_OUTPUT_PREFIX}_{r_class.lower()}")
        hectometer_stake_layer(HECTOR_STAKE_PREFIX,fuse_table)

def stake_length_accurancy(FUSE_PREFIX):
    r_class_list = R_CLASS_LIST[:-1]
    stake_check = stake_AccuracyAsses()
    for r_class in r_class_list:
        stake_check.len_2d_sta(f"{FUSE_PREFIX}_{r_class.lower()}")

if __name__ == "__main__":
    # 原始数据导入
    # if(os.path.exists(report_road_dir)):
    #     load_report_road(report_road_dir, DataIO.PREPROCESSING_INPUT_RP_PREFIX)
    # else:
    #     print("找不到上报路网文件夹路径，请确认是否正确")
    #     exit(1)
    # todo 添加2D

    # 遥感路网
    # if(os.path.exists(remotesensing_road_path)):
    #     load_remote_sensing_road(remotesensing_road_path, DataIO.PREPROCESSING_INPUT_RS)
    # else:
    #     print("找不到遥感路网文件")
    #     exit(1)

    # 遥感路网预处理
    # rs_table_ = RemoteSensingRoadTable(DataIO.PREPROCESSING_INPUT_RS)
    # rs_table_.create_backup("backup")
    # rs_road_preprocessing(DataIO.PREPROCESSING_INPUT_RS)

    # # 上报路网合并和裁剪
    if(os.path.exists(extent_path)):
        extent = load_extent(extent_path)
    else:
        print("找不到裁剪况框文件，默认为None")
        extent = None
    
    # merge_rp_tables(DataIO.PREPROCESSING_INPUT_RP_PREFIX, "rp_all", extent=extent)
    # # 打断上报路网的预处理流程
    # split_rp("rp_all", DataIO.PREPROCESSING_OUTPUT_RP_PREFIX)
    #
    # # 匹配
    # match(DataIO.MATCH_INPUT_RS, DataIO.MATCH_INPUT_RP_PREFIX, DataIO.MATCH_OUTPUT_RS_PREFIX)
    #
    # # # 路网融合
    # # 缓冲区
    # fuse_bufferIteration(DataIO.FUSE_INPUT_RP_PREFIX, DataIO.FUSE_INPUT_RS_PREFIX, DataIO.FUSE_OUTPUT_PREFIX)
    fuse_changeDetect(DataIO.PREPROCESSING_INPUT_RP_PREFIX, DataIO.FUSE_INPUT_RS_PREFIX, DataIO.FUSE_INPUT_RP_PREFIX, DataIO.FUSE_OUTPUT_PREFIX,extent)
    # 融合路网后处理（捕捉）
    RemoteSensingRoadTable(f'{DataIO.MATCH_OUTPUT_RS_PREFIX}_n'.lower()).create_backup("backup")
    fuse_postprocessing(DataIO.FUSE_OUTPUT_PREFIX, DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX)

    # 桩号长度精度
    stake_length_accurancy(DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX)

    # 提取融合路网节点，用于判断桩号方向
    label_rs_nodes(DataIO.FUSE_NODE, DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX)

    # 新增路段编号
    number_all_new_road(DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX)

    # # # 桩号方向计算
    label_stake_direction(DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX, RSNodeTable(DataIO.FUSE_NODE), 10)
    # 百米桩内插
    hectometer_stake_interpolate(DataIO.HECTOR_STAKE_PREFIX,DataIO.FUSE_OUTPUT_PREFIX)
    # 桩号反算
    compute_stakes(r"D:\luwangtiqu\shp\stake_interpolate.shp", r"D:\luwangtiqu\shp\stake_interpolate_result.shp",
                   DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX, DataIO.FUSE_NODE)

    # 提取桩号点
    get_all_stakes("fuse_pt_new", R_CLASS_LIST[-1], DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX)  # 新增路网桩号点
    get_all_stakes("fuse_pt", R_CLASS_LIST[:-1], DataIO.FUSE_POSTPROCESS_OUTPUT_PREFIX)  # 已有路网桩号点
